/*
 * File:   F09.h
 * Author: jcrada
 *
 * Created on 30 May 2011, 12:18 PM
 */

#ifndef ECB_CEC10_F09_H
#define	ECB_CEC10_F09_H

#include "ecb/benchmarks/cec10/CecProblem.h" 

#include "ecb/benchmarks/cec10/CecMath.h"
#include "ecb/operator/Permuted.h"
#include "ecb/operator/Grouped.h"
#include "ecb/operator/Shifted.h"
#include "ecb/benchmarks/cec10/CecRotated.h"
#include "ecb/function/Elliptic.h"


namespace ecb{
    namespace cec10 {

        class F09 : public CecProblem {
        private:
            Function* elliptic;
            std::vector<Function*> sumElliptic;
        public:

            F09(int dimensions, int mValue)
            : CecProblem("F09", "(D/2m)-group Shifted and m-rotated Elliptic Function", dimensions,
            -100, 100, true, mValue, new CecRandom(9l)) {

                std::vector<scalar> shift = CecMath::ShiftVector(dimensions, _properties->getMinimum(), _properties->getMaximum(), randomizer());
                std::vector<int> permutation = CecMath::PermutationVector(dimensions, randomizer());
                std::vector<std::vector<scalar> > rotation = CecMath::RotationMatrix(mValue, randomizer());

                std::vector<scalar> permutedShift(dimensions, 0);
                for (int i = 0; i < dimensions; ++i) {
                    permutedShift[i] = shift[permutation[i]];
                }

                for (int k = 0; k < dimensions / (2 * mValue); ++k) {
                    sumElliptic.push_back(
                            new Permuted(permutation, new Grouped(k * mValue, (k + 1) * mValue,
                            new Shifted(permutedShift, k * mValue, new CecRotated(rotation, new Elliptic())))));
                }

                elliptic = new Permuted(permutation, new Grouped(dimensions / 2, dimensions,
                        new Shifted(permutedShift, dimensions / 2, new Elliptic())));


            }

            ~F09() {
                delete elliptic;
                for (size_t i = 0; i < sumElliptic.size(); ++i) {
                    delete sumElliptic[i];
                }
            }

            scalar f(const std::vector<scalar>& x) {
                scalar result = 0;
                for (size_t i = 0; i < sumElliptic.size(); ++i) {
                    result += sumElliptic[i]->f(x);
                }
                return result + elliptic->f(x);
            }
        };
    }
}

#endif	/* ECB_CEC10_F09_H */

